// Assembler with relocation option-addressing symbols with PC relative
// addressing mode.

#include"hexdec.cpp"
#include"source.cpp"
#include"optbedit.cpp"

class sym
{
 private:
  char symbol[10];
  char addr[5];
  int left,right;
 public:
  sym()   			{ left=0;   right=0;   }
   void setsymbol(char* x)      { strcpy(symbol,x);   }
   void setaddr(char *x)	{ strcpy(addr,x);   }
   void setleft(int x)   	{ left=x;  }
   void setright(int x)		{ right=x; }
   char* retsymbol()   		{ return symbol;   }
   char* retaddr()   		{ return addr;   }
   int retleft()   		{ return left;}
   int retright()		{ return right; }

   void outdata(int i)
    {
     gotoxy(2,i+4);      cout<<symbol;
     gotoxy(18,i+4);     cout<<addr;
    }
}; // end of class

void addsym(sym nu)             // add an object to the symtab
{sym root,t,temp;
 int j,n;
 static int i=0;
 int ptr,prev;
 fstream os;

 os.open("symtab.dat",ios::in|ios::out|ios::binary);
 os.seekg(0,ios::beg);
 os.read((char*)&root,sizeof(root));
 if(root.retleft()==0)
  {i++;
   os.seekp(1*sizeof(sym),ios::beg); os.write((char*)&nu,sizeof(nu));
   os.seekg(0,ios::beg);             os.read((char*)&t,sizeof(t));
   temp.setsymbol(" ");              temp.setaddr(" ");
   temp.setleft(1);                  temp.setright(0);
   os.seekp(0,ios::beg);             os.write((char*)&temp,sizeof(temp));
    }//end of if

   else
    { ptr=1;  i++;
      while(ptr!=0)
       {os.seekg(ptr*sizeof(sym),ios::beg);
	os.read((char*)&t,sizeof(t));
	prev=ptr;
	if(strcmpi(nu.retsymbol(),t.retsymbol()) <= 0 )
	 { ptr=t.retleft(); }
	else
	 {ptr=t.retright(); }

       }  // end of while

       if(strcmpi(nu.retsymbol(),t.retsymbol()) <= 0 )
	   { os.seekp(i*sizeof(sym),ios::beg);	         os.write((char*)&nu,sizeof(nu));
	     os.seekg(prev*sizeof(sym),ios::beg);	 os.read((char*)&t,sizeof(t));
	     temp.setsymbol(t.retsymbol());      	 temp.setaddr(t.retaddr());
	     temp.setleft(i);                		 temp.setright(t.retright());
	     os.seekp(prev*sizeof(sym),ios::beg);	 os.write((char*)&temp,sizeof(temp));	   }
	 else
	  { os.seekp(i*sizeof(sym),ios::beg);		 os.write((char*)&nu,sizeof(nu));
	    os.seekg(prev*sizeof(sym),ios::beg);	 os.read((char*)&t,sizeof(t));
	    temp.setsymbol(t.retsymbol());      	 temp.setaddr(t.retaddr());
	    temp.setleft(t.retleft());          	 temp.setright(i);
	    os.seekp(prev*sizeof(sym),ios::beg);	 os.write((char*)&temp,sizeof(temp));
	   }
	}// end of else
	os.close();
}

int searchsym(char str[])      // search the symbol table
{
 ifstream os;
 sym t;
 int temp,ptr=1;
 os.open("symtab.dat",ios::in|ios::binary);
 os.seekg(0,ios::beg);
 os.read((char*)&t,sizeof(t));
 if(t.retleft()==0){os.close(); return 0;}

 while(ptr!=0)
 { os.seekg(ptr*sizeof(sym),ios::beg);
   os.read((char*)&t,sizeof(t));
   if(strcmpi(str,t.retsymbol()) < 0)
     { ptr=t.retleft(); }
   else if(strcmpi(str,t.retsymbol()) == 0)
     {strcpy(str,t.retaddr()); os.close(); return 1;}
    else  {ptr=t.retright();}
   }  // end of while loop

   return 0;
} // end of search

void pass1()                        // pass1
{
 sym root,t;       //object of symtab
 oprec  op;        // object of source file
 ifstream sfile;   // source file pointer
 int i,j,n;
 char locctr[10],staddr[10],temp[10];
 char length[10];

 sfile.open("source.dat",ios::in|ios::binary); sfile.read((char*)&op,sizeof(op));
 if(strcmpi(op.retmnemonic(),"start")==0)
 {strcpy(staddr,op.retoperand());  strcpy(locctr,op.retoperand()); sfile.read((char*)&op,sizeof(op));}
 else
 { strcpy(locctr,"0"); }

 while(strcmpi(op.retmnemonic(),"end"))
 {
  if(strcmpi(op.retlabel(),"/")!=0)
   { strcpy(temp,op.retlabel());
     if(searchsym(temp)==0)    {root.setsymbol(op.retlabel());root.setaddr(locctr);	 addsym(root);}
	  else                 {cout<<"Duplicate label"<<op.retlabel();getch();exit(0);}
   }// end of if search label

   strcpy(temp,op.retmnemonic());
   // search for opcode
   if(searchop(temp)!=0)              {n=3;hex(locctr,'+',n);}
   else if(strcmpi(temp,"word")==0)   {n=3;hex(locctr,'+',n);}
   else if(strcmpi(temp,"resw")==0)   {n=atoi(op.retoperand());n*=3;hex(locctr,'+',n);}
   else if(strcmpi(temp,"byte")==0)   {n=strlen(op.retoperand());n-=3;hex(locctr,'+',n);}
   else if(strcmpi(temp,"resb")==0)   {n=atoi(op.retoperand());hex(locctr,'+',n);}
   else 			      { cout<<" Error...";getch();exit(0);}

 sfile.read((char*)&op,sizeof(op));
 }// end of while loop

 n=atoi(staddr);strcpy(length,locctr);hex(length,'-',n);
}// end of pass1

void pass2()
{
 sym root,t;    //object of symtab
 outrec out;    // object of outfile
 oprec  op;        // object of source file
 ifstream sfile;   // source file pointer
 ofstream ofile;   // outfile pointer
 int i,j,n,len,len1;
 char locctr[10],taddr[10],tempop[10];
 char temp[10],tempsym[10];
 ofile.open("outfile1.dat",ios::out|ios::binary);

 sfile.open("source.dat",ios::in|ios::binary);
 sfile.read((char*)&op,sizeof(op));
 if(strcmpi(op.retmnemonic(),"start")==0)
 {out.setlabel(op.retlabel());      out.setmnemonic(op.retmnemonic());
  out.setoperand(op.retoperand());  strcpy(locctr,op.retoperand());
  out.setobjcode("000000");         ofile.write((char*)&out,sizeof(out));
  sfile.read((char*)&op,sizeof(op));
 }
 while(strcmpi(op.retmnemonic(),"end"))
 {// search optab for opcode
  strcpy(tempop,op.retmnemonic());
  if(searchop(tempop)!=0)
  {
   n=3;
   hex(locctr,'+',n);
   n=3;
   hex(tempop,'+',n);
   if(strlen(tempop)==1)
   {
	strcpy(temp,"0");
	strcat(temp,tempop);
	strcpy(tempop,temp);
   }
   if(strcmpi(op.retoperand(),"/")!=0)
	 {
	  strcpy(tempsym,op.retoperand());
	  if(searchsym(tempsym)!=0)
	   {
		strcpy(taddr,tempsym);
		len=0;
		hex(locctr,'+',len);
		hex(tempsym,'-',len);
		int l=strlen(tempsym);
		if(l==3)
		{strcpy(temp,"2");
		 strcat(temp,tempsym);
		 strcpy(tempsym,temp);
		}
		else if(l==2)
		{strcpy(temp,"20");
		 strcat(temp,tempsym);
		 strcpy(tempsym,temp);
		}
		else if(l==1)
		{strcpy(temp,"200");
		 strcat(temp,tempsym);
		 strcpy(tempsym,temp);
		}
		else if((l==4)&&(tempsym[0]=='f'))
		{tempsym[0]='2';}
		else
		{strcpy(temp,"10");
		 strcat(temp,taddr);
		 strcpy(tempsym,temp);
		}

		strcat(tempop,tempsym);         	   out.setlabel(op.retlabel());
		out.setmnemonic(op.retmnemonic());         out.setoperand(op.retoperand());
		out.setobjcode(tempop);		           ofile.write((char*)&out,sizeof(out));
	   }
	  else
	   {
		cout<<"undefined symbol"<<op.retoperand();
		getch();
		exit(0);
	   }
	 }
	 else
	 {
	  out.setlabel(op.retlabel());
	  out.setmnemonic(op.retmnemonic());
	  out.setoperand(op.retoperand());
	  strcat(tempop,"0000");
	  out.setobjcode(tempop);
	  ofile.write((char*)&out,sizeof(out));
	 }// end of if /

  }// end of if optab

  else if(strcmpi(tempop,"word")==0)
  {
   n=atoi(op.retoperand());
   strcpy(tempop,"0000");
   hex(tempop,'+',n);
   char temp[10];
   int l=strlen(tempop);
   if(l==4)        {	strcpy(temp,"00");   }
   else if(l==3)   {	strcpy(temp,"000");   }
   else if(l==2)   {    strcpy(temp,"0000");   }
   else if(l==1)   {	strcpy(temp,"00000");   }

   strcat(temp,tempop);
   out.setlabel(op.retlabel());          out.setmnemonic(op.retmnemonic());
   out.setoperand(op.retoperand());      out.setobjcode(temp);
   ofile.write((char*)&out,sizeof(out));

   n=3;
   hex(locctr,'+',n);

  }
  else if(strcmpi(temp,"resw")==0)
   {
	n=atoi(op.retoperand());
	n*=3;
	hex(locctr,'+',n);
   }
  else if(strcmpi(temp,"resb")==0)
   {
	n=atoi(op.retoperand());
	hex(locctr,'+',n);
   }

  else if(strcmpi(tempop,"byte")==0)
  {
   char t[10];
   strcpy(t,op.retoperand());
   int l=strlen(t);
   for(i=2;i<l-1;i++)
	   {tempsym[i-2]=t[i];}   tempsym[l-3]='\0';
	   out.setlabel(op.retlabel());	           out.setmnemonic(op.retmnemonic());
	   out.setoperand(op.retoperand());	   out.setobjcode(tempsym);
	   ofile.write((char*)&out,sizeof(out));
	   n=strlen(op.retoperand());
	   n-=3;
	   hex(locctr,'+',n);
}// end of if-else-if

   sfile.read((char*)&op,sizeof(op));
}// end of while loop
   out.setlabel(op.retlabel());          out.setmnemonic(op.retmnemonic());
   out.setoperand(op.retoperand());      out.setobjcode("");
   ofile.write((char*)&out,sizeof(out));
   sfile.close();                        ofile.close();
}//end of pass2

void main()
{ifstream stab,ofile;
ofstream s;
sym t;
outrec o;
int i=0,j=0;
clrscr();
// following is necessary to keep the root node
s.open("symtab.dat",ios::out|ios::binary);
t.setsymbol(" ");t.setaddr(" ");t.setleft(0);t.setright(0);
s.write((char*)&t,sizeof(t));s.close();


pass1();

cout<<"  SYMBOL TABLE ENTRIES\n";
stab.open("symtab.dat",ios::in|ios::binary);
while(!stab.eof())
 { stab.read((char*)&t,sizeof(t));
  if(!stab.eof())    {t.outdata(i);i++;}
 }
stab.close();
cout<<"\n Press any key to continue...";
getch();

pass2();clrscr();
 cout<<"------------------------------------------------";
 cout<<"\n LABEL      MNEMONIC       OPERAND     OBJCODE";
 cout<<"\n------------------------------------------------";

i=0;ofile.open("outfile1.dat",ios::in|ios::binary);
while(!ofile.eof())
 {ofile.read((char*)&o,sizeof(o));
  if(!ofile.eof())
   {o.display(i);i++;
       if(i==19)
	{i=0;getch();clrscr();
	 cout<<"------------------------------------------------";
	 cout<<"\n LABEL      MNEMONIC       OPERAND     OBJCODE";
	 cout<<"\n------------------------------------------------";
	}
   }
 }ofile.close();
cout<<"\n------------------------------------------------";

getch();

}